package br.com.fieo.sgee.dao;

import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;

/**
 * Classe utilizada para criar a conecção com o banco de dados
 * @param <T> Classe para ser utilizada como template
 * 
 * @author rbueno
 */
public class Dao<T> {

    /** Classe utilizada como template no DAO */
    private Class<T> persistentClass;
    /** Sessao do Hibernate utilizada no banco de dados */
    protected Session session;

    /**
     * Construtor para criar uma nova DAO, contrutor privado obrigando a utilização do factory
     * @param session sessão do hibernate
     * @param persistentClass classe utilizada como template
     */
    protected Dao(Session session, Class<T> persistentClass) {
        this.session = session;
        this.persistentClass = persistentClass;
    }

    /**
     * Método para adicionar um objeto no banco de dados
     * @param u Objeto a ser adicionado no banco de dados
     */
    public void save(T u) {
        this.session.save(u);
    }

    /**
     * Método para remover um objeto do banco de dados
     * @param u Objeto que deve ser removido
     */
    public void delete(T u) {
        this.session.delete(u);
    }

    /**
     * Método para atualizar um objeto do banco de dados
     * @param u Objeto que vai ser atualizado
     */
    public void merge(T u) {
        this.session.merge(u);
    }

    public void update(T u){
        this.session.update(u);
    }

    /**
     * Método para encontrar um registro de uma classe pelo código
     * @param id código de identificação
     * @return Registro encontrado
     */
    public T load(Long id) {
        return (T) session.load(this.persistentClass, id);
    }

    /**
     * Método para retornar todas as intancias de uma determinada classe
     * @return Lista preenchida com todas as instancias
     */
    public List<T> listAll() {
        return this.session.createCriteria(this.persistentClass).list();
    }

    /**
     * Contar a quantidade de registros na base de dados
     * @return Quantidade de itens na base
     */
    protected Integer count() {
        Criteria c = session.createCriteria(persistentClass);
        c.setProjection(Projections.rowCount());
        return (Integer) c.uniqueResult();
    }

    /**
     * Obtém o ultimo registro adicionado no banco de dados
     * @return O Ultimo registro
     */
    public T loadLast() {
        return (T) this.session.createCriteria(persistentClass)
        .addOrder(Order.desc("id"))
        .setMaxResults(1)
        .uniqueResult();
    }
    
}
